#include "game.h"

const qint32 Game::m_refreshRate = 15;
const qint32 Game::m_width = 600;
const qint32 Game::m_height = 600;

Game::Game(QWidget *parent)
    : QWidget(parent)
{
    setWindowTitle(tr("Quagagranda shooter"));

    setFixedSize(m_width, m_height);

    setMouseTracking(true);

    m_background = QPixmap(tr("img/background.jpg"));

    m_isGameStarted = false;

    m_isMovingUp = false;
    m_isMovingDown = false;
    m_isMovingLeft = false;
    m_isMovingRight = false;
    m_mouseX = 0;
    m_mouseY = 0;
    m_isShooting = false;

    m_player = nullptr;

    m_score = 0;

    m_mainTimer = new QTimer(this);
    connect(m_mainTimer, SIGNAL(timeout()), this, SLOT(updateGame()));

    m_asteroidTimer = new QTimer(this);
    connect(m_asteroidTimer, SIGNAL(timeout()), this, SLOT(makeAsteroid()));
    m_asteroidInterval = 500;
    m_updateIndervalFrequency = 5;
    m_generatedCount = 0;

    m_timePlayedTimer = new QElapsedTimer();
    m_timePlayed = 0;
}

Game::~Game()
{
    delete m_player;
    foreach (Bullet *i, bullets)
        delete i;
    foreach (Asteroid *i, asteroids)
        delete i;
    delete m_timePlayedTimer;
}

void Game::start()
{
    if (m_player != nullptr)
        delete m_player;
    m_player = new Player();

    foreach (Bullet *i, bullets)
        delete i;
    bullets.clear();

    foreach (Asteroid *i, asteroids)
        delete i;
    asteroids.clear();

    m_isGameOver = false;
    m_isGameStarted = true;

    m_updateIndervalFrequency = 5;
    m_generatedCount = 0;
    m_asteroidInterval = 500;

    if (!m_mainTimer->isActive())
        m_mainTimer->start(m_refreshRate);
    m_asteroidTimer->start(m_asteroidInterval);
    m_timePlayedTimer->restart();

    m_score = 0;
}

void Game::stop()
{
    m_isGameOver = true;
    m_asteroidTimer->stop();
}

void Game::updateGame()
{
    if (!m_isGameOver)
    {
        // Перемещаем игрока
        qreal dx = 0.0, dy = 0.0;
        if (m_isMovingUp)
            dy -= 1.0;
        if (m_isMovingDown)
            dy += 1.0;
        if (m_isMovingLeft)
            dx -= 1.0;
        if (m_isMovingRight)
            dx += 1.0;
        m_player->move(dx, dy, m_width, m_height);

        // Поворачиваем игрока
        m_player->rotate(m_mouseX, m_mouseY);

        // Стреляем
        if (m_isShooting)
        {
            Bullet *b = m_player->fire();
            if (b != nullptr)
                bullets.append(b);
        }

        // Перемещаем пули и уничтожаем вылетевшие за пределы экрана
        {
            QMutableListIterator<Bullet*> i(bullets);
            while (i.hasNext())
            {
                Bullet *b = i.next();
                b->move();
                if (b->isOutOfField(m_width, m_height))
                {
                    delete b;
                    i.remove();
                }
            }
        }

        // Перемещаем астероиды и уничтожаем вылетевшие за пределы экрана
        {
            QMutableListIterator<Asteroid*> i(asteroids);
            while (i.hasNext())
            {
                Asteroid *a = i.next();
                a->move();
                if (a->isOutOfField(m_width, m_height))
                {
                    delete a;
                    i.remove();
                }
            }
        }

        // Проверка на столкновения астероидов с пулями
        {
            QMutableListIterator<Bullet*> i(bullets);
            while (i.hasNext())
            {
                Bullet *b = i.next();
                QMutableListIterator<Asteroid*> j(asteroids);
                while (j.hasNext())
                {
                    Asteroid *a = j.next();
                    if (b->intersects(a))
                    {
                        delete b;
                        delete a;
                        j.remove();
                        i.remove();
                        ++m_score;
                        break;
                    }
                }
            }
        }

        // Проверка на столкновения астероидов с игроком
        {
            QMutableListIterator<Asteroid*> i(asteroids);
            while (i.hasNext())
            {
                Asteroid *a = i.next();
                if (m_player->intersects(a))
                {
                    stop();
                    break;
                }
            }
        }

        m_timePlayed = m_timePlayedTimer->elapsed();
    }

    repaint();
}

void Game::makeAsteroid()
{
    ++m_generatedCount;
    asteroids.append(new Asteroid(m_width, m_height));
    if (m_generatedCount % m_updateIndervalFrequency == 0)
    {
        m_asteroidTimer->setInterval(std::max(15, m_asteroidInterval -= 15));
        m_generatedCount = 0;
    }
}

void Game::mouseMoveEvent(QMouseEvent *event)
{
    m_mouseX = event->x();
    m_mouseY = event->y();
}

void Game::mousePressEvent(QMouseEvent *)
{
    m_isShooting = true;
}

void Game::mouseReleaseEvent(QMouseEvent *)
{
    m_isShooting = false;
}

void Game::keyPressEvent(QKeyEvent *event)
{
    switch (event->key())
    {
    case Qt::Key_Space:
        if (!m_isGameStarted || m_isGameOver)
            start();
        break;

    case Qt::Key_Escape:
        close();
        break;

    case Qt::Key_W:
    case Qt::Key_Up:
        m_isMovingUp = true;
        break;

    case Qt::Key_A:
    case Qt::Key_Left:
        m_isMovingLeft = true;
        break;

    case Qt::Key_S:
    case Qt::Key_Down:
        m_isMovingDown = true;
        break;

    case Qt::Key_D:
    case Qt::Key_Right:
        m_isMovingRight = true;
        break;
    }
}

void Game::keyReleaseEvent(QKeyEvent *event)
{
    switch (event->key())
    {
    case Qt::Key_W:
    case Qt::Key_Up:
        m_isMovingUp = false;
        break;

    case Qt::Key_A:
    case Qt::Key_Left:
        m_isMovingLeft = false;
        break;

    case Qt::Key_S:
    case Qt::Key_Down:
        m_isMovingDown = false;
        break;

    case Qt::Key_D:
    case Qt::Key_Right:
        m_isMovingRight = false;
        break;
    }
}

void Game::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.drawPixmap(0, 0, m_background);
    if (m_isGameStarted)
    {
        m_player->draw(&painter);
        foreach (Bullet *i, bullets)
            i->draw(&painter);
        foreach (Asteroid *i, asteroids)
            i->draw(&painter);

        painter.setFont(QFont(tr("Times New Roman"), 15));
        painter.setPen(Qt::white);
        painter.drawText(10, 20, tr("Destroyed: %1").arg(m_score));
        painter.drawText(10, 40, tr("Time played: %1.%2 seconds").arg(m_timePlayed / 1000).arg(m_timePlayed / 100 % 10));
        if (m_isGameOver)
        {
            painter.setFont(QFont(tr("Times New Roman"), 36, 5));
            painter.setPen(Qt::black);
            painter.drawText(150, 300, tr("GAME OVER"));
        }
    }
    else
    {
        painter.setFont(QFont(tr("Times New Roman"), 20));
        painter.drawText(135, 300, tr("Press [Space] to start the game"));
    }

}
